package com.slfx.zookeeper.idgen.demo.sequence;

import cn.hutool.core.thread.ExecutorBuilder;
import cn.hutool.core.thread.ThreadFactoryBuilder;
import org.apache.curator.framework.CuratorFramework;
import org.apache.zookeeper.CreateMode;
import org.apache.zookeeper.data.Stat;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ThreadPoolExecutor;


@Component
public class ZkPersistentSequentialDistributedSequence implements DistributedSequence {
    private static final org.slf4j.Logger log = LoggerFactory.getLogger(ZkPersistentSequentialDistributedSequence.class);

    @Resource
    private CuratorFramework client;

    private static String ROOT = "/root";

    /**
     * 提升性能：不需要每次都要判断这个根节点是否存在
     */
    private volatile boolean initFlag;

    public ThreadPoolExecutor commonExecutor = ExecutorBuilder.create()
            .setCorePoolSize(5)
            .setMaxPoolSize(10)
            .setWorkQueue(new LinkedBlockingQueue<>(100))
            .setHandler(new ThreadPoolExecutor.AbortPolicy())
            .setThreadFactory(ThreadFactoryBuilder.create().setNamePrefix("zookeeper-idgen-").build())
            .build();

    public Long sequence(String sequenceName) {
        try {
            //判断节点是否存在，如果不存在，则创建节点
            if (!initFlag) {
                Stat stat = client.checkExists().forPath(ROOT);
                if (stat == null) {
                    String s = client.create().withMode(CreateMode.PERSISTENT).forPath(ROOT);
                }
                initFlag = true;
            }
            String s = generateId(sequenceName);
            return Long.valueOf(s);
        } catch (Exception e) {
            log.error("e:{}", e);
        }
        return null;
    }

    /**
     * 生成id
     *
     * @param sequenceName
     * @return
     */
    public String generateId(String sequenceName) {
        String id = "";
        String backPath = "";
        String fullPath = ROOT.concat("/").concat(sequenceName);
        try {
            // 关键点：创建持久顺序节点
            backPath = client.create().withMode(CreateMode.PERSISTENT_SEQUENTIAL).forPath(fullPath, null);
            //为防止生成的节点浪费系统资源，故生成后异步删除此节点
            String finalBackPath = backPath;
            commonExecutor.execute(() -> {
                try {
                    client.delete().forPath(finalBackPath);
                } catch (Exception e) {
                    log.error("e:{}", e);
                }
            });
            id = splitId(backPath, sequenceName);
            log.info("path:{},生成的id:{}", backPath, id);
        } catch (Exception e) {
            log.error("e:{}", e);
        }
        return id;
    }

    /**
     * * 返回的字符串应该是nameNode + 十位数的一个数字
     * * 这个方法就是拿到返回的拼接字符串截取nameNode后边的数字ID 由于是顺序创建的节点　ID是连续的
     *
     * @param path
     * @param sequenceName
     * @return
     */
    public String splitId(String path, String sequenceName) {
        int index = path.lastIndexOf(sequenceName);
        if (index >= 0) {
            index += sequenceName.length();
            return index <= path.length() ? path.substring(index) : "";
        }
        return path;
    }
}